/**
 *******************************************************************************
 * @file    dpm32m0xx_MATH_ACC.c.
 *
 * @brief   Source file for MATH_ACC firmware driver.
 *          This file provides firmware functions to manage the following
 *          functionalities of the MATH_ACC peripheral :
 *            + Calculate management
 *            + Interrupts, and flags management
 *
 * @author  DPM
 *
 * @version V1.0.0
 *
 * @date    2023-11-01
 *
 * @verbatim
 ===============================================================================
                       ##### How to use this driver #####
 ===============================================================================
    [..]
      (#) Enable peripheral clock using the following functions
          RCC_AHBPeriphClockCmd(RCC_AHB_PERIPH_MATH_ACC, ENABLE).

    ***  Triangal function configuration ***
    =============================================
    [..]
      (#) Enable the MATH_ACC using the MATH_ACC_Cmd() function.

      (#) To configure the MATH_ACC mode with MATH_ACC_MODE_TRIANGLE using 
          MATH_ACC_SetMode() functions.

      (#) To configure the anagle value using MATH_ACC_SetOP0Data() functions.

      (#) To start MATH_ACC calculate, using MATH_ACC_StartCalculate() functions.

      (#) To read the MATH_ACC calculate status, using MATH_ACC_GetFlagStatus()
          function.

      (#) To read the MATH_ACC calculate result, using MATH_ACC_GetOP0Data() and 
          MATH_ACC_GetOP1Data() function.

    ***  Arctangent and taking the modulus function configuration ***
    =============================================
    [..]
      (#) Enable the MATH_ACC using the MATH_ACC_Cmd() function.

      (#) To configure the sin and cos value using MATH_ACC_SetOP0Data() and 
          MATH_ACC_SetOP1Data() functions.

      (#) To configure the MATH_ACC mode with MATH_ACC_MODE_ARCTANGENT_MOD
          using MATH_ACC_SetMode() functions.

      (#) To start MATH_ACC calculate , use the MATH_ACC_StartCalculate() functions.

      (#) To read the MATH_ACC calculate status, use the MATH_ACC_GetFlagStatus()
          function.

      (#) To read the MATH_ACC calculate result, use the MATH_ACC_GetOP0Data() and 
          MATH_ACC_GetOP1Data() function.

    ***  Division function configuration ***
    =============================================
    [..]
      (#) Enable the MATH_ACC using the MATH_ACC_Cmd() function.

      (#) To configure the divisor and dividend value using MATH_ACC_SetOP0Data() and 
          MATH_ACC_SetOP1Data() functions.

      (#) To configure the MATH_ACC mode with MATH_ACC_MODE_DIVISION using 
          MATH_ACC_SetMode() functions.

      (#) To start MATH_ACC calculate , use the MATH_ACC_StartCalculate() functions.

      (#) To read the MATH_ACC calculate status, use the MATH_ACC_GetFlagStatus()
          function.

      (#) To read the MATH_ACC calculate result, use the MATH_ACC_GetOP0Data() and 
          MATH_ACC_GetOP1Data() function.

      (#) MATH_ACC interrupt configuration:
        (+) To activate the MATH_ACC interrupt, using MATH_ACC_IntCmd() functions.
        (+) Check on MATH_ACC interrupt enable flags using the function
            MATH_ACC_GetIntCmdStatus().
        (+) Check on MATH_ACC interrupt occur flags using the function
            MATH_ACC_GetIntFlagStatus().
        (+) Clear MATH_ACC interrupt flags using the function MATH_ACC_ClearIntFlag().

 * @endverbatim
 ******************************************************************************/


#include "dpm32m0xx_math_acc.h"

#if defined (DPM32M05x) || defined (DPM32M03x)

/**
 *******************************************************************************
 * @brief   Enables or disables the specified MATH_ACC peripheral.
 * @param   [in]  NewState: This parameter can be: ENABLE or DISABLE.
 * @retval  None.
 ******************************************************************************/
void MATH_ACC_Cmd(FunctionalState NewState)
{
  if(DISABLE != NewState)
  {
    /* Enable MATH_ACC. */
    MATH_ACC->CR |= MATH_ACC_CR_EN_Msk;
  }
  else
  {
    /* Disable MATH_ACC. */
    MATH_ACC->CR &= ~MATH_ACC_CR_EN_Msk;
  }
}

/**
 *******************************************************************************
 * @brief   Configuration the MATH_ACC calculate mode.
 * @param   [in]  MATH_ACC_Mode: Specifies MATH_ACC calculate mode.
 *                This parameter can be a value of @ref MATH_ACC_ModeEnum.
 *                  @arg MATH_ACC_MODE_TRIANGLE: Calculate triangle functions.
 *                  @arg MATH_ACC_MODE_ARCTANGENT_MOD: Calculating the arctangent 
 *                       and taking the modulus.
 *                  @arg MATH_ACC_MODE_DIVISION: Calculate division.
 * @retval  None.
 ******************************************************************************/
void MATH_ACC_SetMode(MATH_ACC_ModeEnum MATH_ACC_Mode)
{
  MATH_ACC->MODE = (uint32_t)MATH_ACC_Mode;
}

/**
 *******************************************************************************
 * @brief   Set opreat data0 register.
 * @param   [in]  MATH_ACC_OP0: Opreat data0 value.
 * @retval  None.
 ******************************************************************************/
void MATH_ACC_SetOP0Data(int16_t MATH_ACC_OP0)
{
  MATH_ACC->OP0 = (uint32_t)MATH_ACC_OP0;
}

/**
 *******************************************************************************
 * @brief   Set opreat data1 register.
 * @param   [in]  MATH_ACC_OP1: Opreat data1 value.
 * @retval  None.
 ******************************************************************************/
void MATH_ACC_SetOP1Data(int16_t MATH_ACC_OP1)
{
  MATH_ACC->OP1 = (uint32_t)MATH_ACC_OP1;
}

/**
 *******************************************************************************
 * @brief   MATH_ACC start calculate.
 * @retval  None.
 ******************************************************************************/
void MATH_ACC_StartCalculate(void)
{
  MATH_ACC->START = MATH_ACC_START_START_Msk;
}

/**
 *******************************************************************************
 * @brief   Get MATH_ACC calculate flag status.
 * @param   [in]  MATH_ACC_Flag: Specifies MATH_ACC flag.
 *                This parameter can be a value of @ref MATH_ACC_ModeEnum.
 *                  @arg MATH_ACC_FLAG_BUSY: Calculate busy flag.
 *                  @arg MATH_ACC_FLAG_DIV_ZERO: Calculate division zero flag.
 * @retval  FlagState: The state of CAN_PELI_Flag (SET or RESET).
 ******************************************************************************/
FlagState MATH_ACC_GetFlagStatus(MATH_ACC_FlagEnum MATH_ACC_Flag)
{
  /* Return the status of the interrupt enable bit. */
  return (FlagState)((MATH_ACC->SR & (MATH_ACC_Flag))
                                 ? SET : RESET);
}

/**
 *******************************************************************************
 * @brief   Clear the status flag bit when performing division with a divisor of 0.
 * @retval  None.
 ******************************************************************************/
void MATH_ACC_ClearDivZeroFlag(void)
{
  MATH_ACC->SR = MATH_ACC_SR_DIV_ZERO_IF_Msk;
}

/**
 *******************************************************************************
 * @brief   Get opreat data0 register.
 * @retval  int16_t: opreat data0 value.
 ******************************************************************************/
int16_t MATH_ACC_GetOP0Data(void)
{
  return (int16_t)MATH_ACC->OP0;
}

/**
 *******************************************************************************
 * @brief   Get opreat data1 register.
 * @retval  int16_t: opreat data1 value.
 ******************************************************************************/
int16_t MATH_ACC_GetOP1Data(void)
{
  return (int16_t)MATH_ACC->OP1;
}

/**
 *******************************************************************************
 * @brief   Calculate triangle value.
 * @param   [in]  MATH_ACC_Anagle: anagle value.
 * @param   [out] MATH_ACC_Sin: Calculate sin value.
 * @param   [out] MATH_ACC_Cos: Calculate cos value.
 * @retval  MATH_ACC_CalResultEnum: Calculate result.
 *          This parameter can be a value of @ref MATH_ACC_CalResultEnum.
 *            @arg MATH_ACC_CAL_RESULT_FAIL: Calculate fail.
 *            @arg MATH_ACC_CAL_RESULT_SUCCESS: Calculate success.
 ******************************************************************************/
MATH_ACC_CalResultEnum  MATH_ACC_CalTriangle(int16_t MATH_ACC_Anagle, int16_t* MATH_ACC_Sin, int16_t* MATH_ACC_Cos)
{
  uint32_t timeCount = 0UL;
  
  /* Parameters check. */
  if(MATH_ACC_Sin == NULL || MATH_ACC_Cos == NULL)
    return MATH_ACC_CAL_RESULT_FAIL;

  MATH_ACC->MODE = MATH_ACC_MODE_TRIANGLE;

  MATH_ACC->OP0 = (uint32_t)MATH_ACC_Anagle;
  
  MATH_ACC->START = MATH_ACC_START_START_Msk;
  
  /* Wait calculate finish. */
  do
  {
    /* Calculate timeout. */
    if(timeCount >= MATH_ACC_TIMEOUT_VALUE)
      return MATH_ACC_CAL_RESULT_FAIL;

    timeCount++;
  } while ((MATH_ACC->SR & (MATH_ACC_SR_BUSY_Msk)) != 0x00u);
  
  *MATH_ACC_Sin = (int16_t)MATH_ACC->OP0;
  
  *MATH_ACC_Cos = (int16_t)MATH_ACC->OP1;
  
  return MATH_ACC_CAL_RESULT_SUCCESS;
}

/**
 *******************************************************************************
 * @brief   Calculate arctangent and modul value.
 * @param   [in]  MATH_ACC_Sin: Input sin value.
 * @param   [in]  MATH_ACC_Cos: Input cos value.
 * @param   [out] MATH_ACC_Arct: Calculate arctangent value.
 * @param   [out] MATH_ACC_Mod: Calculate modul value.
 * @retval  MATH_ACC_CalResultEnum: Calculate result.
 *          This parameter can be a value of @ref MATH_ACC_CalResultEnum.
 *            @arg MATH_ACC_CAL_RESULT_FAIL: Calculate fail.
 *            @arg MATH_ACC_CAL_RESULT_SUCCESS: Calculate success.
 ******************************************************************************/
MATH_ACC_CalResultEnum  MATH_ACC_CalArctAndMod(int16_t MATH_ACC_Sin, int16_t MATH_ACC_Cos, \
                                               int16_t* MATH_ACC_Arct, int16_t* MATH_ACC_Mod)
{
  uint32_t timeCount = 0UL;
  
  /* Parameters check. */
  if(MATH_ACC_Arct == NULL || MATH_ACC_Mod == NULL)
    return MATH_ACC_CAL_RESULT_FAIL;

  MATH_ACC->MODE = MATH_ACC_MODE_ARCTANGENT_MOD;

  MATH_ACC->OP0 = (uint32_t)MATH_ACC_Sin;
  
  MATH_ACC->OP1 = (uint32_t)MATH_ACC_Cos;

  MATH_ACC->START = MATH_ACC_START_START_Msk;
  
  /* Wait calculate finish. */
  do
  {
    /* Calculate timeout. */
    if(timeCount >= MATH_ACC_TIMEOUT_VALUE)
      return MATH_ACC_CAL_RESULT_FAIL;

    timeCount++;
  } while ((MATH_ACC->SR & (MATH_ACC_SR_BUSY_Msk)) != 0x00u);

  *MATH_ACC_Mod = (int16_t)MATH_ACC->OP0;

  *MATH_ACC_Arct = (int16_t)MATH_ACC->OP1;
  
  return MATH_ACC_CAL_RESULT_SUCCESS;
}

/**
 *******************************************************************************
 * @brief   Calculate quotations and remainder value.
 * @param   [in]  MATH_ACC_Divisor: Input divisor value.
 * @param   [in]  MATH_ACC_Dividend: Input dividend value.
 * @param   [out] MATH_ACC_Quotations: Calculate quotations value.
 * @param   [out] MATH_ACC_Remainder: Calculate remainder value.
 * @retval  MATH_ACC_CalResultEnum: Calculate result.
 *          This parameter can be a value of @ref MATH_ACC_CalResultEnum.
 *            @arg MATH_ACC_CAL_RESULT_FAIL: Calculate fail.
 *            @arg MATH_ACC_CAL_RESULT_SUCCESS: Calculate success.
 ******************************************************************************/
MATH_ACC_CalResultEnum  MATH_ACC_CalDivision(int16_t MATH_ACC_Divisor, int16_t MATH_ACC_Dividend, \
                                             int16_t* MATH_ACC_Quotations, int16_t* MATH_ACC_Remainder)
{
  uint32_t timeCount = 0UL;
  
  /* Parameters check. */
  if(MATH_ACC_Quotations == NULL || MATH_ACC_Remainder == NULL)
    return MATH_ACC_CAL_RESULT_FAIL;
  
  MATH_ACC->MODE = MATH_ACC_MODE_DIVISION;

  MATH_ACC->OP0 = (uint32_t)MATH_ACC_Dividend;

  MATH_ACC->OP1 = (uint32_t)MATH_ACC_Divisor;

  MATH_ACC->START = MATH_ACC_START_START_Msk;
  
  /* Wait calculate finish. */
  do
  {
    /* Calculate timeout. */
    if(timeCount >= MATH_ACC_TIMEOUT_VALUE)
      return MATH_ACC_CAL_RESULT_FAIL;
    
    timeCount++;
  } while (((MATH_ACC->SR & (MATH_ACC_SR_BUSY_Msk)) != 0x00u));

  /* Calculate err. */
  if((MATH_ACC->SR & MATH_ACC_SR_DIV_ZERO_IF_Msk) != 0x00u)
  {
    MATH_ACC->SR = MATH_ACC_SR_DIV_ZERO_IF_Msk;
    return MATH_ACC_CAL_RESULT_FAIL;
  }

  *MATH_ACC_Quotations = (int16_t)MATH_ACC->OP0;
  
  *MATH_ACC_Remainder = (int16_t)MATH_ACC->OP1;
  
  return MATH_ACC_CAL_RESULT_SUCCESS;
}

/**
 *******************************************************************************
 * @brief   Enable or disable the specifies MATH_ACC interrupt.
 * @param   [in]  NewState: This parameter can be: ENABLE or DISABLE.
 * @retval  None.
 ******************************************************************************/
void MATH_ACC_IntCmd(FunctionalState NewState)
{
  if(DISABLE != NewState)
  {
    /* Enable MATH_ACC interrupt. */
    MATH_ACC->CR |= MATH_ACC_CR_DONE_IE_Msk;
  }
  else
  {
    /* Disable MATH_ACC interrupt. */
    MATH_ACC->CR &= ~MATH_ACC_CR_DONE_IE_Msk;
  }
}

/**
 *******************************************************************************
 * @brief   Get MATH_ACC interrupt enable status.
 * @retval  FunctionalState: The MATH_ACC enable interrupt state(ENABLE or DISABLE).
 ******************************************************************************/
FunctionalState MATH_ACC_GetIntCmdStatus(void)
{
  /* Return the status of the interrupt enable bit. */
  return (FunctionalState)((MATH_ACC->CR & (MATH_ACC_CR_DONE_IE_Msk))
                           ? ENABLE : DISABLE);
}

/**
 *******************************************************************************
 * @brief   Get the MATH_ACC interrupt flag status.
 * @retval  FlagState: The new state of MATH_ACC interrupt(SET or RESET).
 ******************************************************************************/
FlagState MATH_ACC_GetIntFlagStatus(void)
{
  if((MATH_ACC->SR & MATH_ACC_SR_DONE_IF_Msk) != RESET)
  {
    return SET;
  }
  else
  {
    return RESET;
  }
}

/**
 *******************************************************************************
 * @brief   Clear the MATH_ACC interrupt flag.
 * @retval  None.
 ******************************************************************************/
void MATH_ACC_ClearIntFlag(void)
{
  /* Soft write 1 to clear interrupt status. */
  MATH_ACC->SR = MATH_ACC_SR_DONE_IF_Msk;
}

#endif
